---
title: Parse a page expression
summary: Converts a page expression string into an array of PageRange.
status: draft
owner: SAIF Doc Gen
last_reviewed: 2026-09-17
library: PdfAPI.Core
reference_type: package
operation_id: OP-11
trigger: PageRange.Parse(string) invoked
---

# Parse a page expression

This operation parses a comma-separated page-expression string (e.g., `"1-5,7,9-*,*"`) into an array of `PageRange` selections consumed by [Extract pages](op-08-extract-pages.md).

| Field | Value |
| --- | --- |
| **Operation ID** | OP-11 |
| **Trigger** | Caller invokes `PageRange.Parse(string text)` |
| **Inputs** | Page expression string |
| **Outputs** | Array of `PageRange` (possibly empty) |
| **Primary components** | `PdfAPI.Core.PageRange.Parse` |
| **Entry point** | `PdfAPI.Core\Extract\PageRange.cs` |

## Steps

1. Split the expression on commas. ([BR-25](../business-rules.md#br-25-page-expression-token-grammar))
2. Match each token against `((?<start>\d+)-(?<stop>(\d*|\*)))|(?<page>(\d+|\*))`; silently skip non-matching tokens. ([BR-25](../business-rules.md#br-25-page-expression-token-grammar), [BR-26](../business-rules.md#br-26-unmatched-tokens-are-skipped-silently))
3. For a `start-stop` token, parse both numbers and normalise a stop of zero or less to `-1` (open-ended). ([BR-27](../business-rules.md#br-27-absent-or-non-positive-stop-page-is-open-ended))
4. For a bare `*`, add an all-pages range (`1` to `-1`). ([BR-28](../business-rules.md#br-28-asterisk-means-all-pages))
5. For a bare page number, add a single-page range. ([BR-29](../business-rules.md#br-29-bare-page-number-is-a-single-page-range))
6. Return the accumulated array (possibly empty when nothing matched). ([BR-26](../business-rules.md#br-26-unmatched-tokens-are-skipped-silently))

`DocumentRange.Create(document, pages)` defaults `pages` to `"*"`, and `DocumentRange`'s private constructor substitutes a default all-pages `PageRange` when the supplied array is null or empty ([BR-30](../business-rules.md#br-30-empty-page-ranges-default-to-all-pages)).

## Process flow

The following diagram visualizes this operation's control flow.

```mermaid
flowchart TD
	Start(["Parse(text)"]) --> Split["Split on commas"]
	Split --> Loop{For each token}
	Loop --> Match{Matches grammar?}
	Match -->|No| Loop
	Match -->|start-stop| Range["Parse start/stop,<br>normalize stop <= 0 to -1"]
	Match -->|*| All["Add all-pages range<br>(1 to -1)"]
	Match -->|number| Single["Add single-page range"]
	Range --> Loop
	All --> Loop
	Single --> Loop
	Loop -->|Done| Return([Return PageRange array])
```

## Failure and edge-case behavior
- An entirely unmatched expression yields an empty range array rather than an exception ([BR-26](../business-rules.md#br-26-unmatched-tokens-are-skipped-silently)).
- A null or empty page-range array supplied to `DocumentRange`'s constructor defaults to all pages ([BR-30](../business-rules.md#br-30-empty-page-ranges-default-to-all-pages)).

## Related documentation
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)
- [Security and authorization](../security-authorization.md)

## Sources
- `PdfAPI.Core\Extract\PageRange.cs`
- `PdfAPI.Core\Extract\DocumentRange.cs`
